﻿module;

//#include "log.h"

export module fast_utils:map_utils;

export namespace fast::util{

    /**
     * @note
     * map<string, int>::key_type  v1; //此时key_type的v1类型是string
     * map<string, int>::mapped_type  v2; //此时mapped_type的v2类型是int
     * map<string, int>::value_type  v3; //此时value_type的v3类型是pair<const string, int>，注意pair键值对中第一个元素的类型有const(不可修改).
     */
    class MapUtil {
    public:

        /**
         *@brief 给定一个映射和一个键，返回对应于映射中的键的值，如果键不存在于映射中，则返回给定的默认值。
         *@code <pre>
         *
         *  MapUtil map_util;
         *
         *  std::map<std::string, std::string> map{
         *	    {"this", "100"},
         *  	{"can", "100"},
         *      {"be", "100"},
         *      {"const", "100"},
         *	};
         *
         *	auto default_value = map_util.GetDefault(map, "undefined");
         *
         *	LOG_INFO << typeid(default_value).name();
         *
         *
         * </pre>
         */
        template<typename Map, typename Key>
        static typename Map::mapped_type GetDefault(const Map &map, const Key &key) {
            auto pos = map.find(key);
            return (pos != map.end()) ? (pos->second) : (typename Map::mapped_type{});
        }

        /**
        *@brief 给定一个映射和一个键，返回对映射中与键对应的值的引用，如果映射中不存在该键，则返回给定的默认引用。
        *@code <pre>
        *
        *  MapUtil map_util;
        *
        *  std::map<std::string, std::string> map{
        *	  {"this", "100"},
        *  	  {"can", "100"},
        *      {"be", "100"},
        *      {"const", "100"},
        *	};
        *
        *  std::string mapped_type_value = "abcd";
        *  auto mapped_type_default_value = map_util.GetRefDefault(map, "undefined", mapped_type_value);
        *
        *  LOG_INFO << typeid(mapped_type_default_value).name();
        *
        *  LOG_INFO << mapped_type_default_value;
        *
        *  if (mapped_type_default_value == mapped_type_value) {
        *	 LOG_INFO << &mapped_type_default_value << "value is equal,but memory address not equal" << &mapped_type_value;
        *  }
        * </pre>
        */
        template<class Map, typename Key = typename Map::key_type>
        static const typename Map::mapped_type &GetRefDefault(
                const Map &map, const Key &key, const typename Map::mapped_type &dflt) {
            auto pos = map.find(key);
            return (pos != map.end() ? pos->second : dflt);
        }

        /**
         * 传递临时默认值会在返回时返回一个悬空引用，生命周期延长被间接破坏了。
         * 调用者必须确保默认值比 GetRefDefault() 返回的引用生命周期长。
         */
        template<class Map, typename Key = typename Map::key_type>
        static const typename Map::mapped_type &GetRefDefault(
                const Map &map, const Key &key, typename Map::mapped_type &&dflt) = delete;

        template<class Map, typename Key = typename Map::key_type>
        static const typename Map::mapped_type &GetRefDefault(
                const Map &map,
                const Key &key,
                const typename Map::mapped_type &&dflt) = delete;

        /**
         *@brief 给定一个映射和一个键，返回一个指向对应于映射中键的值的指针，如果键不存在于映射中，则返回 nullptr。
         *@code <pre>
         *
         *  MapUtil map_util;
         *
         *  std::map<std::string, std::string> map{
         *	    {"this", "100"},
         *  	{"can", "100"},
         *      {"be", "100"},
         *      {"const", "100"},
         *	};
         *
         *  // 默认 auto 带有const
         *  auto *const_ptr= map_util.GetConstPtr(map, "this");
         *
         * </pre>
         */
        template<class Map, typename Key = typename Map::key_type>
        static const auto *GetConstPtr(const Map &map, const Key &key) {
            auto pos = map.find(key);
            return (pos != map.end() ? &pos->second : nullptr);
        }

        /**
         *@brief 非const 获取 ptr
         *@code <pre>
         *
         *  MapUtil map_util;
         *
         *  std::map<std::string, std::string> map{
         *	  {"this", "100"},
         *  	  {"can", "100"},
         *      {"be", "100"},
         *      {"const", "100"},
         *	};
         *
         *  auto *ptr = map_util.GetPtr(map, "this");
         *
         *  *ptr = "200";
         *
         *  LOG_INFO << map["this"];
         * </pre>
         */
        template<class Map, typename Key = typename Map::key_type>
        static auto *GetPtr(Map &map, const Key &key) {
            auto pos = map.find(key);
            return (pos != map.end() ? &pos->second : nullptr);
        }

        template<class Map, typename Key = typename Map::key_type>
        static void printfMap(Map &map, const Key &key) {
            for (const auto &item: map) {

                //LOG_INFO << item.first << "   " << item.second;
            }
        }


    };// MapUtil
}